home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NOVA - For the NeXT Workstation
/
NOVA - For the NeXT Workstation.iso
/
SourceCode
/
AdobeExamples
/
NX_ImportAdv
/
epsfreader.m
< prev
next >
Wrap
Text File
|
1992-12-19
|
14KB
|
555 lines
/*
* (a) (C) 1990 by Adobe Systems Incorporated. All rights reserved.
*
* (b) If this Sample Code is distributed as part of the Display PostScript
* System Software Development Kit from Adobe Systems Incorporated,
* then this copy is designated as Development Software and its use is
* subject to the terms of the License Agreement attached to such Kit.
*
* (c) If this Sample Code is distributed independently, then the following
* terms apply:
*
* (d) This file may be freely copied and redistributed as long as:
* 1) Parts (a), (d), (e) and (f) continue to be included in the file,
* 2) If the file has been modified in any way, a notice of such
* modification is conspicuously indicated.
*
* (e) PostScript, Display PostScript, and Adobe are registered trademarks of
* Adobe Systems Incorporated.
*
* (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
* CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
* AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
* ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
* OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
* WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
* WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
* DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
* OF THIRD PARTY RIGHTS.
*/
/*
* epsfparser.m
*
* ReadEpsf() is the procedure to invoke for parsing. It takes a pointer
* to a structure as an argument. This structure contains the pointer to
* the data as well as the locations to place the results of the parsing.
* This parser grabs the bounding box and the fonts. Other parsers
* can add to this general structure to do more sophisticated parsing
* such as page breakout and such.
*
* Version: 2.0
* Author: Ken Fromm
* History:
* 03-19-91 Added this comment.
*/
#import "epsfstruct.h"
#import <appkit/nextstd.h>
#import <objc/hashtable.h>
#import <objc/List.h>
#import <objc/Storage.h>
#import <strings.h>
static int processToField(EpsfStruct *epsf);
static int processToLineEnd(EpsfStruct *epsf);
static int processBBox(EpsfStruct *epsf);
static int processIncludeFile(EpsfStruct *epsf);
static int processToEndDocument(EpsfStruct *epsf);
static int processDocumentResource(EpsfStruct *epsf);
static int processPageCount(EpsfStruct *epsf);
/*
* These static CommentHandle arrays are organized
* into different groups according to the level of the
* parsing. The general comments handle the top most
* level of parsing. The document comments handle
* the parsing of an included document.
*
* This setup allows the same general flow to handle the
* parsing of each group. When a comment is reached
* that indicates another level of parsing should be
* performed, the tables for that level is passed to the
* processToComment procedure.
*
* Others group could be added (not necessarily for
* Epsf inclusion but for print management parsing). One
* example is a page comment group. This group would
* parse the page comments breaking out the location
* of the individual pages as well as fonts, colors, paper
* sizes, etc.
*
*/
typedef struct {
char *comment; int (*proc) (EpsfStruct *epsf);
} CommentHandle;
/***** General comments *****/
static CommentHandle generalComments [ ] =
{
{"%%BoundingBox:", processBBox},
{"%%BeginDocument", processToEndDocument},
{"%%Document", processDocumentResource},
{"%%Pages:", processPageCount}
};
/***** Document comments *****/
static CommentHandle documentIncludeComments [ ] =
{
{"%%BeginDocument", processToEndDocument},
{"%%IncludeFile", processIncludeFile}
};
/***** Document comments *****/
static CommentHandle documentEndComments [ ] =
{
{"%%EndDocument", processToLineEnd}
};
/*
* These static arrays are used to recognize the types of resources.
* For starters there are at present 5 types of resources - fonts, files,
* procsets, patterns and forms. Within each type, there are 3 states -
* present, needed and supplied. The present state is the union of the
* needed and supplied. The needed means the resource is not included
* with the document. The supplied means the resource is included with
* the document.
*/
typedef struct {
char *comment; int key;
} ResourceHandle;
/***** Resource comments *****/
static ResourceHandle resourceStates [ ] =
{
{"Needed", RES_NEEDED},
{"Supplied", RES_SUPPLIED}
};
static ResourceHandle resourceTypeMain [ ] =
{
{"Fonts", RES_FONTS},
{"Files", RES_FILES},
{"ProcSets", RES_PROCSETS},
{"Patterns", RES_PATTERNS},
{"Forms", RES_FORMS},
{"Resources", RES_RESOURCES},
};
static ResourceHandle resourceTypeSub [ ] =
{
{"fonts", RES_FONTS},
{"files", RES_FILES},
{"procsets", RES_PROCSETS},
{"patterns", RES_PATTERNS},
{"forms", RES_FORMS}
};
/*
* This is the workhorse of the parser. It takes a general structure
* and some pointers to CommentHandle arrays and processes
* the data until the one of the comments in the endTable has
* been reached or the data runs out. Any matches to the
* processTable comments processes the comment without
* returning. (Any match to the endTable returns after processing.)
*
* If endLength is 0 then we will only process until the next line that
* is not a comment.
*/
static int processToComment(EpsfStruct *epsf, CommentHandle endTable[ ], int endLength,
CommentHandle processTable[ ], int processLength)
{
int i, j;
while (epsf->data < epsf->enddata)
{
if (strncmp(epsf->data, "%", 1) == 0)
{
for (j = 0; j < endLength; j++)
{
if (strncmp(epsf->data, endTable[j].comment,
strlen(endTable[j].comment)) == 0)
{
return endTable[j].proc(epsf);
}
}
for (i = 0; i < processLength; i++)
{
if (strncmp(epsf->data, processTable[i].comment,
strlen(processTable[i].comment)) == 0)
{
processTable[i].proc(epsf);
break;
}
}
if (i == processLength)
processToLineEnd(epsf);
}
else
{
/* If endLength == 0 then process until the next non-comment. */
if (endLength == 0)
return EPSF_OK;
else
processToLineEnd(epsf);
}
}
return EPSF_OK;
}
static int CheckEpsf(EpsfStruct *epsf)
{
int rc = EPSF_INVALIDPS;
if (strncmp(epsf->data, "%!PS-Adobe-", 11) == 0)
{
processToField(epsf);
if (strncmp(epsf->data, "EPSF-", 5) == 0)
{
processToLineEnd(epsf);
rc = EPSF_OK;
}
}
return rc;
}
void CheckEpsfBinaryHeader(char **data, int *len)
{
EpsfBinaryHeader *header;
char *newdata;
int newlen;
/*
* If a binary header file is encountered then just skip
* to the PostScript section of the file. Update the
* data and len arguments to reflect this change.
*/
header = (EpsfBinaryHeader *) *data;
if (header->idbytes == EPSF_BINARYID)
{
newdata = *data + header->ps_start;
newlen = header->ps_length;
if (newdata >= *data && newdata + newlen <= *data + *len)
{
*data = newdata;
*len = newlen;
}
}
}
/*
* This is the routine invoked for parsing. It validates the file
* as a proper EPSF file (by checking for the %!PS-Adobe or
* for the binary header id) and then parses the file.
*/
int ReadEpsf(EpsfStruct *epsf)
{
int rc = EPSF_OK;
if (epsf && epsf->filedata && *epsf->filedata)
{
CheckEpsfBinaryHeader(&epsf->filedata, &epsf->filelen);
epsf->data = epsf->filedata;
epsf->enddata = epsf->filedata + epsf->filelen;
if (epsf->data < epsf->enddata && !CheckEpsf(epsf))
{
bzero(epsf->bbox, sizeof(epsf->bbox));
bzero(&epsf->resources, sizeof(epsf->resources));
bzero(&epsf->inclusions, sizeof(epsf->inclusions));
while (epsf->data < epsf->enddata && !rc)
{
rc = processToComment(epsf,
generalComments, sizeof(generalComments)/sizeof(CommentHandle),
NULL, 0);
}
/* Check for a valid bounding box. */
if (!rc && epsf->bbox[0] == 0 && epsf->bbox[1] == 0 &&
epsf->bbox[2] == 0 && epsf->bbox[3] == 0)
rc = EPSF_INVALIDBBOX;
}
else
rc = EPSF_INVALIDPS;
}
else
rc = EPSF_INVALIDPS;
return rc;
}
static int processToNonSpace(EpsfStruct *epsf)
{
while (epsf->data < epsf->enddata && *epsf->data == ' ')
epsf->data++;
return EPSF_OK;
}
static int processToField(EpsfStruct *epsf)
{
while (epsf->data < epsf->enddata && *epsf->data != ':' && *epsf->data != ' ')
epsf->data++;
if (epsf->data < epsf->enddata && *epsf->data == ':')
epsf->data++;
processToNonSpace(epsf);
return EPSF_OK;
}
static int processToLineEnd(EpsfStruct *epsf)
{
while (epsf->data < epsf->enddata && *epsf->data != '\n')
epsf->data++;
if (epsf->data < epsf->enddata)
epsf->data++;
return EPSF_OK;
}
static int processBBox(EpsfStruct *epsf)
{
int rc = EPSF_OK;
processToField(epsf);
if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0)
if ((sscanf(epsf->data, "%f %f %f %f", &epsf->bbox[0], &epsf->bbox[1],
&epsf->bbox[2], &epsf->bbox[3]) != 4) ||
epsf->bbox[2] <= epsf->bbox[0] || epsf->bbox[3] <= epsf->bbox[1])
rc = EPSF_INVALIDBBOX;
processToLineEnd(epsf);
return rc;
}
static int processIncludeFile(EpsfStruct *epsf)
{
int rc = EPSF_OK;
char name[EPSF_MAXLINE];
Inclusion inclusion;
bzero(&inclusion, sizeof(inclusion));
inclusion.offset = epsf->data - epsf->filedata;
processToField(epsf);
if (epsf->data < epsf->enddata)
{
if (sscanf(epsf->data, "%s", name))
inclusion.filename = NXUniqueString(name);
processToLineEnd(epsf);
inclusion.len = (epsf->data - epsf->filedata) - inclusion.offset;
if (inclusion.filename)
{
if (!epsf->inclusions)
epsf->inclusions= [Storage newCount:0 elementSize:sizeof(Inclusion) description:InclusionDescription];
[epsf->inclusions addElement:&inclusion];
}
}
else
rc = EPSF_INVALIDDOCUMENT;
return rc;
}
static int processToEndDocument(EpsfStruct *epsf)
{
processToLineEnd(epsf);
processToComment(epsf,
documentEndComments,
sizeof(documentEndComments)/sizeof(CommentHandle),
documentIncludeComments,
sizeof(documentIncludeComments)/sizeof(CommentHandle));
if (epsf->data >= epsf->enddata)
return EPSF_INVALIDDOCUMENT;
else
return EPSF_OK;
}
/* Checks the page count. If greater than 1, an error is returned. */
/* Eps files should be single page documents only. */
static int processPageCount(EpsfStruct *epsf)
{
int rc = EPSF_OK;
int pagetotal = 0;
processToField(epsf);
if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0)
if (sscanf(epsf->data, "%d", &pagetotal))
if (pagetotal > 1)
rc = EPSF_INVALIDPAGECOUNT;
processToLineEnd(epsf);
return rc;
}
static int checkResource(EpsfStruct *epsf, ResourceHandle table[ ], int length)
{
int i;
for (i = 0; i < length; i++)
{
if (epsf->data < epsf->enddata &&
strncmp(epsf->data, table[i].comment, strlen(table[i].comment)) == 0)
{
epsf->data += strlen(table[i].comment);
return table[i].key;
}
}
return -1;
}
static int processResourceLine(EpsfStruct *epsf, int type, int state)
{
int i;
char name[EPSF_MAXLINE], temp[40];
if (!epsf->resources[type].states[state])
epsf->resources[type].states[state] = [List new];
processToNonSpace(epsf);
while (epsf->data < epsf->enddata && *epsf->data != '\n')
{
sscanf(epsf->data, "%s", name);
epsf->data += strlen(name);
processToNonSpace(epsf);
if (type == RES_PROCSETS)
{
for (i = 0; i < 2 && epsf->data < epsf->enddata && *epsf->data != '\n'; i++)
{
if (sscanf(epsf->data, "%s", temp))
{
strcat(name, " ");
strcat(name, temp);
epsf->data += strlen(temp);
processToNonSpace(epsf);
}
}
}
[epsf->resources[type].states[state]
addObjectIfAbsent:(id) NXUniqueString(name)];
}
return EPSF_OK;
}
static int processResources(EpsfStruct *epsf, int xtype, int state)
{
int done = FALSE, type;
type = xtype;
processToField(epsf);
if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0)
{
while (epsf->data < epsf->enddata && !done )
{
processToNonSpace(epsf);
if (*epsf->data == '\n')
{
epsf->data++;
if (epsf->data < epsf->enddata && strncmp(epsf->data, "%%+", 3) == 0)
epsf->data += 3;
else
done = TRUE;
}
else
{
if (xtype == RES_RESOURCES)
type = checkResource(epsf, resourceTypeSub,
sizeof(resourceTypeSub)/sizeof(ResourceHandle));
if (type >= RES_FONTS && type <= RES_FORMS)
processResourceLine(epsf, type, state);
else
while (epsf->data < epsf->enddata && *epsf->data != '\n')
epsf->data++;
}
}
}
else
processToLineEnd(epsf);
return EPSF_OK;
}
static int processDocumentResource(EpsfStruct *epsf)
{
int state, type;
epsf->data += 10;
if (epsf->data < epsf->enddata)
{
state = checkResource(epsf, resourceStates,
sizeof(resourceStates)/sizeof(ResourceHandle));
state = MAX(RES_PRESENT, state);
type = checkResource(epsf, resourceTypeMain,
sizeof(resourceTypeMain)/sizeof(ResourceHandle));
if (type >= 0)
processResources(epsf, type, state);
}
return EPSF_OK;
}
static char *getResource(int key, ResourceHandle table[ ], int length)
{
int i;
for (i = 0; i < length; i++)
if (table[i].key == key)
return table[i].comment;
return NULL;
}
void GetDocumentComment(char *comment, int type, int state)
{
char *subOne, *subTwo;
strcpy(comment, "%%%%Document");
subOne = getResource(state, resourceStates,
sizeof(resourceStates)/sizeof(ResourceHandle));
if (subOne)
strcat(comment, subOne);
subTwo = getResource(type, resourceTypeMain,
sizeof(resourceTypeMain)/sizeof(ResourceHandle));
if (subTwo)
strcat(comment, subTwo);
strcat(comment, ": ");
}
const char *GetTypeComment(int type)
{
return getResource(type, resourceTypeMain,
sizeof(resourceTypeMain)/sizeof(ResourceHandle));
}